/**************************************************************
 * @file     bsp_key_irq.c
 * @brief    实现按键驱动队列发送消息，基于中断检测按键单击，长按检测
 * @author   Ruilist
 * @date     2025-07-30
 * @version  V1.0.0
 * @copyright Copyright (c) 2025
 *
 * @note     1 tab = 4 space
 *
 * @par 日志:
 * - V1.0.0 2025-07-30 Ruilist
 *   实现按键驱动队列发送消息
 **************************************************************/

#include "bsp_key_irq.h"

osThreadId_t key_TaskHandle;

const osThreadAttr_t key_Task_attributes = {
    .name       = "key_Task",
    .stack_size = 128 * 4,
    .priority   = (osPriority_t)osPriorityNormal,
};

QueueHandle_t key_queue       = NULL;
QueueHandle_t inter_key_queue = NULL;

/**
 * @brief   按键任务
 *
 * @param   *argument    任务默认参数
 *
 * @return  空
 *
 */
void key_task_func( void *argument )
{
    uint32_t          event_index        = 0;
    uint32_t          frist_trigger_tick = 0;
    key_press_event_t key_press_event    = { .edge_type = RISING, .trigger_tick = 0 };

    key_press_event_t *p_key_press_event = NULL;

    key_queue       = xQueueCreate( 10, sizeof( key_press_status_t ) );
    inter_key_queue = xQueueCreate( 10, 4 );

    if ( NULL == key_queue || NULL == inter_key_queue )
    {
        printf( "key_queue or inter_key_queue created failed \r\n" );
        return;
    }
    else
    {
        printf( "key_queue and inter_key_queue created successfully \r\n" );
    }

    for ( ;; )
    {
        printf( "key_task_func running  at [%d] tick \r\n", HAL_GetTick() );
        if ( pdTRUE == xQueueReceive( inter_key_queue, &( p_key_press_event ), (TickType_t)0 ) )
        {
            key_press_event.edge_type    = p_key_press_event->edge_type;
            key_press_event.trigger_tick = p_key_press_event->trigger_tick;

            printf( "key_press_event.trigger_tick = [%d]\r\n", key_press_event.trigger_tick );
            printf( "inter_key_queue receive key event at [%d] tick \r\n", HAL_GetTick() );
            if ( RISING == key_press_event.edge_type &&
                 0 == event_index )
            {
                printf( "key RASING fetched! error!" );
            }
            if ( FAILING == key_press_event.edge_type && 0 == event_index )
            {
                printf( "key FAILING fetched! first\r\n" );

                event_index += 1;

                frist_trigger_tick = key_press_event.trigger_tick;
            }
            if ( RISING == key_press_event.edge_type && 1 == event_index )
            {
                printf( "key RASING after the falling " );

                if ( key_press_event.trigger_tick - frist_trigger_tick < 10 )
                {

                    printf( "Invalid key fetched at [%d] tick \r\n", HAL_GetTick() );
                    event_index = 0;
                    continue;
                }

                if ( ( key_press_event.trigger_tick - frist_trigger_tick ) < 1000 )
                {
                    key_press_status_t key_result = KEY_SHORT_PRESSED;

                    if ( pdTRUE == xQueueSendToFront( key_queue, &key_result, 0 ) )
                    {
                        printf( "key_result send short press successfully at [%d] tick \r\n", HAL_GetTick() );
                        event_index = 0;
                    }
                    else
                    {
                        printf( "key_result send short press failed at [%d] tick \r\n", HAL_GetTick() );
                    }
                }
                if ( ( key_press_event.trigger_tick - frist_trigger_tick ) > 1000 )
                {
                    key_press_status_t key_result = KEY_LONG_PRESSED;

                    if ( pdTRUE == xQueueSendToFront( key_queue, &key_result, 0 ) )
                    {
                        printf( "key_result send long press successfully"
                                " at [%d] tick \r\n",
                                HAL_GetTick() );
                        event_index = 0;
                    }
                    else
                    {
                        printf( "key_result send long press failed at [%d] tick \r\n", HAL_GetTick() );
                    }
                }
            }
        }
        osDelay( 100 );
    }
}

/**
 * @brief   按键状态轮询
 *
 * @param   *key_value    用作按键状态传参
 *
 * @return  函数状态 key_status_t
 *
 */

key_status_t key_scan( key_press_status_t *key_value )
{
    key_press_status_t key_status_value = KEY_NOT_PRESSED;

    if ( GPIO_PIN_RESET == HAL_GPIO_ReadPin( KEY_GPIO_Port, KEY_Pin ) )
    {
        key_status_value = KEY_PRESSED;
        *key_value       = key_status_value;
        return KEY_OK;
    }

    *key_value = key_status_value;

    return KEY_ERRORTIMEOUT;  // 始终没有按键被按下，返回超时
}

/**
 * @brief   检测按键单击，长按状态
 *
 * @param   *key_value    按键触发状态传参
 * @param   threshold_time    单击检测时间阈值
 *
 * @return  函数状态 key_status_t
 *
 */
key_status_t key_long_short_press( key_press_status_t *key_value, uint32_t threshold_time )
{
    key_status_t       ret_key_status = KEY_OK;
    key_press_status_t temp_key_value = KEY_NOT_PRESSED;
    uint32_t           time_counter   = 0;

    ret_key_status = key_scan( &temp_key_value );

    if ( KEY_OK == ret_key_status )
    {
        if ( KEY_PRESSED == temp_key_value )
        {
            time_counter = HAL_GetTick();
            while ( HAL_GetTick() < time_counter + threshold_time )
                ;
            ret_key_status = key_scan( &temp_key_value );
            if ( KEY_NOT_PRESSED == temp_key_value )
            {
                *key_value = KEY_SHORT_PRESSED;
                return KEY_OK;
            }
            else
            {
                *key_value = KEY_LONG_PRESSED;
                while ( KEY_OK == key_scan( &temp_key_value ) )
                    ;
                return KEY_OK;
            }
        }
    }
    return ret_key_status;
}

/**
 * @brief   按键中断回调函数
 *
 * @param   void
 *
 * @return  void
 *
 */
KEY_CALLBACK
{
    HAL_GPIO_WritePin( IRQ_TRACE_GPIO_Port, IRQ_TRACE_Pin, GPIO_PIN_SET );

    static uint32_t irq_type = FALING_TYPE;

    static key_press_event_t key_press_event_1 = { .edge_type = FAILING, .trigger_tick = 0 };
    static key_press_event_t key_press_event_2 = { .edge_type = RISING, .trigger_tick = 0 };

    key_press_event_t *p_key_press_event_1 = &key_press_event_1;
    key_press_event_t *p_key_press_event_2 = &key_press_event_2;

    BaseType_t xHigherPrioritTaskWoken;

    if ( FALING_TYPE == irq_type )
    {
        if ( NULL == inter_key_queue )
        {
            printf( "inter_key_queue not created at [%d] tick \r\n", HAL_GetTick() );
        }
        key_press_event_1.trigger_tick = HAL_GetTick();
        if ( pdTRUE == xQueueSendToFrontFromISR( inter_key_queue, &p_key_press_event_1, &xHigherPrioritTaskWoken ) )
        {
            printf( "key_press_event send FALING_event successfully at [%d] tick \r\n", HAL_GetTick() );
        }

        irq_type = RISING_TYPE;

        GPIO_InitTypeDef GPIO_InitStruct = { 0 };

        GPIO_InitStruct.Pin  = KEY_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init( KEY_GPIO_Port, &GPIO_InitStruct );
    }
    else if ( RISING_TYPE == irq_type )
    {
        if ( NULL == inter_key_queue )
        {
            printf( "inter_key_queue not created at [%d] tick \r\n", HAL_GetTick() );
        }
        key_press_event_2.trigger_tick = HAL_GetTick();
        if ( pdTRUE == xQueueSendToFrontFromISR( inter_key_queue, &p_key_press_event_2, &xHigherPrioritTaskWoken ) )
        {
            printf( "key_press_event send RASING_event successfully at [%d] tick \r\n", HAL_GetTick() );
        }

        irq_type = FALING_TYPE;

        GPIO_InitTypeDef GPIO_InitStruct = { 0 };

        GPIO_InitStruct.Pin  = KEY_Pin;
        GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        HAL_GPIO_Init( KEY_GPIO_Port, &GPIO_InitStruct );
    }
    HAL_GPIO_WritePin( IRQ_TRACE_GPIO_Port, IRQ_TRACE_Pin, GPIO_PIN_RESET );
}
